import React, { useRef, useState, ChangeEvent } from 'react'
import Loading from '../icons/loading'
import "./switch.scss"

/**
 * @param disabled 是否禁用
 * @param loading 是否显示加载中
 * @param size switch 的大小
 * @param activeIcon switch 状态为 on 时所显示图标，设置此项会忽略 active-text
 * @param inactiveIcon switch 状态为 off 时所显示图标，设置此项会忽略 inactive-text
 * @param activeText switch 打开时的文字描述
 * @param inactiveText switch 的状态为 off 时的文字描述
 * @param activeValue switch 状态为 on 时的值
 * @param inactiveValue switch的状态为 off 时的值
 * @param name switch 对应的 name 属性
 * @param beforeChange switch 状态改变前的钩子， 返回 false 或者返回 Promise 且被 reject 则停止切换
 * @param id input 的 id
 * @param tabindex input 的 tabindex
 * @param ariaLabel 等价于原生 input aria-label 属性
 * @param activeAction 选中时的文本
 * @param inactiveAction 未选中时的文本
 * @param defaultValue 初始值
 */
interface Props {
    disabled?: boolean,
    loading?: boolean,
    size?: 'small' | 'default' | 'large'
    activeIcon?: React.ReactNode,
    inactiveIcon?: React.ReactNode,
    activeText?: string,
    inactiveText?: string,
    activeValue?: boolean | string | number,
    inactiveValue?: boolean | string | number,
    name?: string,
    beforeChange?: boolean | Function,
    id?: string,
    tabindex?: number,
    ariaLabel?: string,
    activeAction?: React.ReactNode,
    inactiveAction?: React.ReactNode,
    defaultValue?: boolean | string | number
    change?: (value: boolean | string | number) => void
}

const Switch = ({
    disabled = false,
    loading = false,
    size = "default",
    activeIcon,
    inactiveIcon,
    activeText,
    inactiveText,
    activeValue = true,
    inactiveValue = false,
    name,
    beforeChange = true,
    id,
    tabindex,
    ariaLabel,
    activeAction,
    inactiveAction,
    defaultValue = false,
    change = () => { }
}: Props) => {
    const sizeArr = ["small", "large"]

    const [value, setValue] = useState<boolean | string | number>(defaultValue)
    const [loadingFlag, setLoadingFlag] = useState<boolean>(false)
    const [disabledFlag, setDisabledFlag] = useState<boolean>(false)
    const inputRef = useRef<HTMLInputElement>(null)

    const onClick = async () => {
        let flag = true
        if (typeof beforeChange === 'boolean') {
            flag = beforeChange
        } else if (typeof beforeChange === 'function') {
            setLoadingFlag(true)
            setDisabledFlag(true)
            try {
                flag = await beforeChange()
            } finally {
                setLoadingFlag(false)
                setDisabledFlag(false)
            }
        }
        if (flag) {
            inputRef.current?.click()
        }
    }

    const onChange = (event: ChangeEvent<HTMLInputElement>) => {
        setValue(event.target.checked ? activeValue : inactiveValue)
        change(event.target.checked ? activeValue : inactiveValue)
    }

    const getValue = (value: boolean | string | number) => {
        if (typeof value === 'boolean') {
            return value ? 1 : 0
        } else {
            return value
        }
    }

    return (
        <div
            className={["pe-switch", (loading || loadingFlag) || (disabled || disabledFlag) ? 'is-disabled' : '', sizeArr.includes(size) ? `pe-switch-${size}` : ''].join(" ").trim()}
            style={{ cursor: (loading || loadingFlag) || (disabled || disabledFlag) ? 'not-allowed' : 'pointer' }}
            onClick={(e) => {
                e.stopPropagation()
                onClick()
            }}
        >
            {
                inactiveIcon || inactiveIcon === 0 || inactiveText ? (
                    <span className="pe-switch-off-text"
                        style={{ color: value === inactiveValue ? 'var(--pe-switch-on-color)' : '' }}>
                        {inactiveIcon}
                        {
                            !inactiveIcon && inactiveText ? inactiveText : null
                        }
                    </span>
                ) : null
            }
            <div className={["pe-switch-main", value === activeValue ? 'is-checked' : ''].join(" ").trim()} style={{
                backgroundColor: value === activeValue ? 'var(--pe-switch-on-color)' : 'var(--pe-switch-off-color)',
                border: `2px solid var(--pe-switch-${value === activeValue ? 'on' : 'off'}-color)`
            }}>
                <input ref={inputRef} className="pe-switch-input" type="checkbox" true-value={getValue(activeValue)}
                    false-value={getValue(inactiveValue)} disabled={disabled || disabledFlag} name={name} id={id}
                    tabIndex={tabindex} aria-label={ariaLabel} onChange={(e): any => {
                        onChange(e)
                    }} onClick={(e): any => {
                        e.stopPropagation()
                    }} />
                <div className="pe-switch-item">
                    {
                        loading || loadingFlag ? <Loading /> : null
                    }
                    <div style={{ color: value === activeValue ? 'var(--pe-switch-on-color)' : 'var(--pe-switch-on-color)' }}>
                        {
                            value === activeValue ? activeAction : inactiveAction
                        }
                    </div>
                </div>
            </div>
            {
                activeIcon || activeIcon === 0 || activeText ? (
                    <span className="pe-switch-on-text"
                        style={{ color: value === activeValue ? 'var(--pe-switch-on-color)' : '' }}>
                        {activeIcon}
                        {
                            !activeIcon && activeText ? activeText : null
                        }
                    </span>
                ) : null
            }
        </div>
    )
}

export default Switch